package cn.jbolt.core.api.log;

import cn.hutool.http.useragent.Browser;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import cn.jbolt.core.annotation.JBoltApiLog;
import cn.jbolt.core.api.JBoltApiLogKit;
import cn.jbolt.core.bean.IpRegion;
import cn.jbolt.core.util.JBoltDateUtil;
import cn.jbolt.core.util.JBoltIpUtil;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.kit.Okv;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;


public class JBoltApiLogInterceptor implements Interceptor {
    private final Log LOG = Log.getLog("JBoltApiLog");

    @Override
    public void intercept(Invocation invocation) {
        Method method = invocation.getMethod();
        Okv apiLogInfo = Okv.create();
        apiLogInfo.set("createTime", JBoltDateUtil.getNowStr(JBoltDateUtil.YMDHMSS));
        apiLogInfo.set("title",invocation.getActionKey());
        boolean needProcessApiLog =  method.isAnnotationPresent(JBoltApiLog.class);
        if(needProcessApiLog){
            JBoltApiLog an = method.getAnnotation(JBoltApiLog.class);
            if(an.ignore()){
                LOG.info("单独忽略了此action的日志记录:"+invocation.getActionKey());
                invocation.invoke();
                return;
            }
            String title = an.value();
            if(StrKit.notBlank(title)){
                apiLogInfo.set("title",title);
            }
            JBoltApiLogKit.init(apiLogInfo);
        }
        try {
            invocation.invoke();
            Controller controller = invocation.getController();
            HttpServletRequest request = controller.getRequest();
            apiLogInfo.set("controller",controller.getClass().getName());
            apiLogInfo.set("action",invocation.getMethodName());
            apiLogInfo.set("api",invocation.getActionKey());
            apiLogInfo.set("httpMethod",request.getMethod());
            apiLogInfo.set("args",invocation.getArgs());
            apiLogInfo.set("params",controller.getParaMap());
            apiLogInfo.set("urlParams",controller.getPara());
            apiLogInfo.set("returnValue",invocation.getReturnValue());

            //获取IP地址
            String ip= JBoltIpUtil.getIp(controller.getRequest());
            apiLogInfo.set("ip",ip);
            if("unknown".equals(ip) || "127.0.0.1".equals(ip)) {
                apiLogInfo.set("address","");
            }else {
                boolean needReadAddressByIp= PropKit.getBoolean("baidu_map_get_address_by_ip", false);
                if(needReadAddressByIp) {
                    //通过百度地图API 拿到地址
                    processAddressByBaiduMapApi(apiLogInfo);
                }else {
                    //通过ip2region 拿到地址
                    processAddressByIp2Region(apiLogInfo);
                }
            }
            //处理日志中关于系统 平台 浏览器等信息的记录
            processOsBrowserInfo(request,apiLogInfo);
            //执行持久化
            store(apiLogInfo);
        }finally {
            if(needProcessApiLog){
                JBoltApiLogKit.clear();
            }
        }
    }

    private void processOsBrowserInfo(HttpServletRequest request, Okv apiLogInfo) {
        UserAgent userAgent= UserAgentUtil.parse(request.getHeader("User-Agent"));
        if(userAgent!=null) {
            apiLogInfo.set("isMobile",userAgent.isMobile());
            String osName=userAgent.getOs().getName();
            apiLogInfo.set("osName",osName);
            apiLogInfo.set("osPlatformName",userAgent.getPlatform().getName());
            Browser browser=userAgent.getBrowser();
            apiLogInfo.set("isBrowser",browser!=null);
            if(browser!=null) {
                apiLogInfo.set("browserName",browser.getName());
                apiLogInfo.set("browserVersion",userAgent.getVersion());
                apiLogInfo.set("browserEngineName",userAgent.getEngine().getName());
                apiLogInfo.set("browserEngineVersion",userAgent.getEngineVersion());
            }
        }
    }

    private void processAddressByIp2Region(Okv apiLogInfo) {
        IpRegion ipRegion=JBoltIpUtil.toAddressByIp2Region(apiLogInfo.getStr("ip"));
        if(ipRegion == null) {
            apiLogInfo.set("address","XXXX");
        }else {
            String address = ipRegion.getAddress();
            if(StrKit.isBlank(address)) {
                apiLogInfo.set("address","XXXX");
            }else {
                apiLogInfo.set("address",address);
                String country=ipRegion.getCountry();
                if(StrKit.notBlank(country)&&!("0".equals(country))) {
                    apiLogInfo.set("country",country);
                }
                String province=ipRegion.getProvince();
                if(StrKit.notBlank(province)&&!("0".equals(province))) {
                    apiLogInfo.set("province",province);
                }
                String city=ipRegion.getCity();
                if(StrKit.notBlank(city)&&!("0".equals(city))) {
                    apiLogInfo.set("city",city);
                }
            }
        }
    }

    private void processAddressByBaiduMapApi(Okv apiLogInfo) {
        //通过百度API 拿到address信息
        JSONObject addressJsonObject=JBoltIpUtil.toAddressByBaiduMapApi(apiLogInfo.getStr("ip"));
        if(addressJsonObject == null) {
            apiLogInfo.set("address","XXXX");
        }else {
            apiLogInfo.set("address",addressJsonObject.getString("address"));
            JSONObject addressDetail=addressJsonObject.getJSONObject("address_detail");
            if(addressDetail != null) {
                apiLogInfo.set("country","中国");
                apiLogInfo.set("province",addressDetail.getString("province"));
                apiLogInfo.set("city",addressDetail.getString("city"));
                apiLogInfo.set("cityCode",addressDetail.getString("city_code"));
                JSONObject point=addressDetail.getJSONObject("point");
                if(point != null) {
                    apiLogInfo.set("latitude",point.getString("x"));
                    apiLogInfo.set("longitude",point.getString("y"));
                }
            }
        }
    }

    /**
     * 持久化 自行实现
     * 默认写入log文件里
     * @param apiLogInfo
     */
    private void store(Okv apiLogInfo) {
        LOG.info(apiLogInfo.toJson());
    }
}
